import java.text.ParseException;
import java.text.SimpleDateFormat;

public class NBHeatMeterDecode {

    public static void main(String[] args) {
        NBHeatMeter meter = new NBHeatMeterDecode().decode("202310200232123B682063028232004D22812E1F90000000000011380500001171090000173907010035903401002C153100292300645400204302201023200000E716202310200611543B682063028232004D22812E1F90000000000011510500001187090000173507010035853801002C223100352300685400032306201023200000EF16");
        System.out.println(meter);
    }

    public NBHeatMeter decode(String hexStr) {
        byte[] bytes = hexStringToByte(hexStr);
        int idx = 10;
        SimpleDateFormat sdf = new SimpleDateFormat("ssmmHHddMMyyyy");
        NBHeatMeter meter = new NBHeatMeter();
        String addr = byteToHexStringFlip(bytes, idx, 4);
        meter.setAddress(addr);
        idx += 12;
        float accCold = (float) (Integer.parseInt(byteToHexStringFlip(bytes, idx, 4)) * 0.01);
        idx += 4;
        meter.setCold(toKwh(accCold, bytes[idx++] & 0xff));
        float accHeat = (float) (Integer.parseInt(byteToHexStringFlip(bytes, idx, 4)) * 0.01);
        idx += 4;
        meter.setAccHeat(toKwh(accHeat, bytes[idx++] & 0xff));
        float power = (float) (Integer.parseInt(byteToHexStringFlip(bytes, idx, 4)) * 0.01);
        idx += 4;
        meter.setHeat(toKw(power, bytes[idx++] & 0xff));
        float flow = (float) (Integer.parseInt(byteToHexStringFlip(bytes, idx, 4)) * 0.0001);
        idx += 4;
        meter.setFlow(toM3h(flow, bytes[idx++] & 0xff));
        float accFlow = (float) (Integer.parseInt(byteToHexStringFlip(bytes, idx, 4)) * 0.01);
        idx += 4;
        meter.setAccFlow(toM3(accFlow, bytes[idx++]));
        meter.setSupplyTemp((float) (Integer.parseInt(byteToHexStringFlip(bytes, idx, 3)) * 0.01));
        idx += 3;
        meter.setReturnTemp((float) (Integer.parseInt(byteToHexStringFlip(bytes, idx, 3)) * 0.01));
        idx += 3;
        meter.setWorkTime(Integer.parseInt(byteToHexStringFlip(bytes, idx, 3)));
        idx += 3;
        try {
            meter.setDate(sdf.parse(byteToHexString(bytes, idx, 7)));
        } catch (ParseException e) {
            
        }
        idx += 7;
        meter.setStatus(byteToHexString(bytes, idx, 2));
        meter.setFault(heatMeterFaults(meter.getStatus()));
        return meter;
    }

    private static byte[] hexStringToByte(String str) {
        str = str.replaceAll(" ", "");
        byte[] bytes = new byte[str.length() / 2];
        for (int i = 0; i < str.length() / 2; i++) {
            String subStr = str.substring(i * 2, i * 2 + 2);
            bytes[i] = (byte) Integer.parseInt(subStr, 16);
        }
        return bytes;
    }

    private static String byteToHexString(byte[] b, int offSet, int length) {
        StringBuilder sb = new StringBuilder();
        int end = offSet + length;
        if (offSet >= 0 && length > 0 && end <= b.length) {
            for (int index = offSet; index < end; index++) {
                sb.append(String.format("%02X", b[index]));
            }
        }
        return sb.toString();
    }

    private static String byteToHexStringFlip(byte[] b, int offSet, int length) {
        StringBuilder sb = new StringBuilder();
        int end = offSet + length;
        if (offSet >= 0 && length > 0 && end <= b.length) {
            for (int index = end - 1; index >= offSet; index--) {
                sb.append(String.format("%02X", b[index]));
            }
        }
        return sb.toString();
    }

    private static float toKwh(float src, int unit) {
        switch (unit) {
            case 0x02:
                return src / 1000;
            case 0x08:
                return src * 1000;
            case 0x0a:
                return  src * 1000 * 100;
            case 0x01:
                return (float) (src / 1000000000 * 277.8);
            case 0x0b:
                return (float) (src / 1000000 * 277.8);
            case 0x0e:
                return (float) (src / 1000 * 277.8);
            case 0x11:
                return (float) (src * 277.8);
            default:
        }
        return src;
    }

    static float toKw(float src, int unit) {
        switch (unit) {
            case 0x14:
                return src / 1000;
            case 0x1a:
                return src * 1000;
            default:
        }
        return src;
    }

    private static float toM3(float src, int unit) {
        if (unit == 0x29) {
            return src / 1000;
        }
        return src;
    }

    private static float toM3h(float src, int unit) {
        if (unit == 0x32) {
            return src / 1000;
        }
        return src;
    }

    private static String heatMeterFaults(String status) {
        int hexCode = Integer.parseInt(status, 16);
        StringBuilder faults = new StringBuilder();
        if ((hexCode >> 10 & 1) == 1) {
            faults.append("电池欠压,");
        }
        if ((hexCode >> 7 & 1) == 1) {
            faults.append("无水,");
        }
        if ((hexCode >> 6 & 1) == 1) {
            faults.append("逆流,");
        }
        if ((hexCode >> 2 & 1) == 1) {
            faults.append("回水故障,");
        }
        if ((hexCode >> 1 & 1) == 1) {
            faults.append("进水故障,");
        }
        return faults.toString();
    }

}
